<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * A base model with a series of CRUD functions (powered by CI's query builder)
 * 
 * @author phamngockhanh262@gmail.com
 * @copyright 2013 phamngockhanh262@gmail.com
 * @link 
 * @package CodeIgniter
 * @subpackage core
 */
class MY_Model extends CI_Model 
{
    /**
     * This model's default database table
     * @var string
     */
    public $table = '';
    
    /**
     * This model's default primary key
     * Used by the update(), delete() and getById() functions.
     * @var string
     */
    public $primary = 'id';

    public function __construct()
    {
        parent::__construct();
        $this->load->database();
    }
    
    /**
     * Insert a new row into the table
     * 
     * @param array $data
     * @return int Return the ID of the inserted row
     */
    public function create(array $data) 
    {
        $this->db->insert($this->table, $data);
        return $this->db->insert_id();
    }

    /**
     * Updated a record based on the primary value
     * 
     * @param int $id
     * @param array $data
     * @param boolean $affected_rows
     * @return int Return the number of rows updated (alway 0 or 1)
     */
    public function update($id, array $data, $affectedRows = FALSE) 
    {
        $this->db->where($this->primary, $id)
                 ->update($this->table, $data);
        if ($affectedRows) {         
            return $this->db->affected_rows();
        }
    }
    
    /**
     * Creates or Alters a record in the table
     * 
     * @param array $data
     * @return int Return the ID of the inserted row or the number of rows updated
     */
    public function save(array $data = array())
    {
        if (isset($data[$primary])) {
            return $this->update($data[$primary], $data);
        } else {
            return $this->add($data);
        }
    }

    /**
     * Delete a row from the table by the primary value
     * 
     * @param int $id
     * @return int Return the number of rows deleted
     */
    public function delete($id) 
    {
        $this->db->where($this->primary, $id)
                 ->delete($this->table);
        return $this->db->affected_rows();
    }
    
    /**
     * Fetch all the records in the table
     * @note Used Options Array help:
     * - avoid duplication code
     * - add function parameters just change methods and will not have to update code anywhere else.
     * Example for used 'where'
     * <code>
     * $this->user_model->getAll(array(
     *     'select' => 'user_id, email',
     *     'where'  => array(
     *         'user_id'  => '1',
     *         'email !=' => '2', 
     *     ),
     * ));
     * </code>
     * Example for used 'where' (not recommend)
     * <code>
     * $this->user_model->getAll(array(
     *     'select' => 'user_id, email',
     *     'where'  => 'user_id = 1 AND email != 2',
     * ));
     * </code>
     *  
     * @param array|NULL $options values is select, limit, offset, 
     *                                      where (array or string), like (array or string), 
     *                                      order array, 
     * @return array Returns the query result as a pure array, or an empty array when no result is produced
     */
    public function getAll(array $options = array()) 
    {
        if (isset($options['select'])) {
            $this->db->select("{$options['select']}");
        }
        
        if (isset($options['where'])) {
            $this->db->where($options['where']);
        }
        
        if (isset($options['like'])) {
            $this->db->like($options['like']);
        }
        
        if (isset($options['order'])){
            $order = $options['order'];
            foreach ($order as $key => $value) {
                $this->db->order_by($key, $value);
            }
        }
        
        if (isset($options['limit']) && isset($options['offset'])) {
            $this->db->limit($options['limit'], $options['offset']);
        } else if (isset($options['limit'])) {
            $this->db->limit($options['limit']);
        }
        
        return $this->db->get($this->table)
                        ->result_array();
    }
    
    /**
     * Fetch a single record based on the primary key
     * 
     * @param int $id
     * @param string $select
     * @return array Returns a single result row pure array, or an empty array when no result is produced
     */
    public function getById($id, $select = NULL)
    {
        if (isset($select)) {
            $this->db->select($select);
        }
        
        return $this->db->where($this->primary, $id)
                        ->limit(1)
                        ->get($this->table)
                        ->row_array();
    }
    
    /**
     * Determine the number of rows in a particular table
     * 
     * @return int
     */
    public function countAll()
    {
        return $this->db->count_all($this->table);
    }
    
    /**
     * Return the next auto increment of the table. 
     * 
     * @return int
     */
    public function getNextId()
    {
        return $this->db->select('AUTO_INCREMENT')
                        ->from('information_schema.TABLES')
                        ->where('TABLE_NAME', $this->table)
                        ->get()
                        ->row()
                        ->AUTO_INCREMENT;
    }
}